package so.sao.code.service.infrastructure.context;

import com.google.common.util.concurrent.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import so.sao.code.service.domain.entity.TagTask;
import so.sao.code.service.infrastructure.WebContext;
import so.sao.code.service.infrastructure.context.strategy.TaskRetryStrategy;
import so.sao.code.service.infrastructure.enums.TASK_STATUS;
import so.sao.code.service.repository.TagTaskDao;
import so.sao.ffw.feign.client.QueueMessageDetectionClient;

import javax.annotation.Nullable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Created by Administrator on 2017/10/11.
 */
public class TaskContext<T> {
    TagTask tagTask;
    Consumer<T> action;
    TagTaskDao tagTaskDao = WebContext.context.getBean(TagTaskDao.class);
    T message;
    QueueMessageDetectionClient queueMessageDetectionClient = WebContext.context.getBean(QueueMessageDetectionClient.class);
    TaskRetryStrategy taskRetryStrategy = new TaskRetryStrategy();
    ListeningExecutorService asyncTask = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
    ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(2);
    int retry = 0;
    private static Logger log = LoggerFactory.getLogger(TaskContext.class);

    public TaskContext() {
    }

    /**
     * tagTask 要执行的task 标记task是否已完成
     * action 任务中对应的动作
     */
    public TaskContext(T message, TagTask tagTask, Consumer<T> action) {
        this.message = message;
        this.tagTask = tagTask;
        this.action = action;
    }

    //异步执行可能激活状态有延迟 base原理
    public void execute() {
        pre();
        doExecute();
    }

    private int retry() {
        return retry++;
    }

    public void doExecute() {
        ListenableFuture listenableFuture = asyncTask.submit(() -> action.accept(message));
        Futures.addCallback(listenableFuture, new FutureCallback<Object>() {
            @Override
            public void onSuccess(@Nullable Object result) {
                //成功后更新任务状态
                after();
            }

            @Override
            public void onFailure(Throwable t) {
                if (taskRetryStrategy.shouldRetry("", t, retry())) {
                    retryExecutor.schedule(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (checkMessageIsSuccess()) return;
                                doExecute();
                            } catch (Exception ex) {
                                if (retry == taskRetryStrategy.getMaxRetryTimes()) {
                                    //发送邮件，ffw服务不可用
                                    log.error("任务失败" + ex.getMessage());
                                    return;
                                }
                                doExecute();
                            }
                        }
                    }, taskRetryStrategy.getPauseDelay("", t, retry()), TimeUnit.MILLISECONDS);
                }
            }
        });

    }

    //消息发送失败,调用ffw接口确认消息是否已经收到
    private boolean checkMessageIsSuccess() {
        return queueMessageDetectionClient.getLocalMessageIdFromFfw(tagTask.getGuid());
    }


    private void pre() {
        //tagTask = getTagTask();
        if (tagTask.getStatus() != TASK_STATUS.UNDO) return;
        tagTask.setStatus(TASK_STATUS.DOING);
        tagTaskDao.save(tagTask);
    }

    //更新任务表的状态和码段激活状态
    private void after() {
        tagTask.setStatus(TASK_STATUS.DONE);
        tagTaskDao.save(tagTask);
    }
//    private TagTask getTagTask() {
//        //唯一标识 一个 激活任务
//        String uuid = rangeActivation.getSeqnumStart() + "-" + rangeActivation.getProductId() + "-" + rangeActivation.getFactoryId();
//        return tagTaskDao.findByPayload(uuid);
//    }
}
